/*
* Copyright 2010 Competentum group
*
* Licensed under the GNU General Public License, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.gnu.org/licenses/gpl.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.competentum.lib.data.builders
{
	import com.competentum.lib.data.vo.UniqueVO;
	
	import flash.events.EventDispatcher;
	
	import mx.collections.ArrayCollection;

	/**
	 * Abstract DataBuilder Class for all dataBuilders.
	 * Supports adding, removing of items, checking for unque IDs.
	 * Usually subclass must implement concrete method for creating items, e. g.:
	 * public function createStaticLabel(x:Number, y:Number, value:String, uid:String = null, addToArray:Boolean = true):StaticLabelVO
	 *  
	 * @author Valentine Abanosimov
	 */	
	public class AbstractDataBuilder extends EventDispatcher
	{
		private var _type:String = "AbstractDataBuilder";
		public function get type():String
		{
			return _type;
		}
		public function set type(value:String):void
		{
			_type = value;
		}

		[Bindable]
		protected var _items:ArrayCollection = new ArrayCollection();
		public function get items():ArrayCollection
		{
			return _items;
		}
		public function get itemsVector():Vector.<UniqueVO>
		{
			var result:Vector.<UniqueVO> = new Vector.<UniqueVO>();
			for (var i:int = 0; i < _items.length; i ++ )
			{
				result.push(_items.getItemAt(i));
			}
			return result;
		}
		
		/**
		 * Base string that is used for generating UIDs
		 * */
		private var uidBase:String;

		public function get global():Boolean
		{
			return false;
		}

		public function AbstractDataBuilder(type:String = null, uidBase:String = '')
		{
			super();
			this.type = type;
			this.uidBase = uidBase;
		}
		
		/**
		 * Number of items
		 * */
		public function get itemsCount():int
		{
			return _items.length;
		}
		
		/**
		 * Adds item to items vector.
		 */
		public function addItem(item:UniqueVO):UniqueVO
		{
			_items.addItem(item);
			validateUID(item);
			return item;
		}
		
		/**
		 * Return item by its UID
		 * */
		public function getItemByUid(uid:String):UniqueVO
		{
			for each (var item:UniqueVO in _items)
			{
				if (item.uid == uid)
					return item;
			}
			return null;
		}
		
		/**
		 * Return item by its index
		 * */
		public function getItemByIndex(index:int):UniqueVO
		{
			return _items[index];
		}
		
		/**
		 * Removes setted vector from vectors item.
		 */
		public function removeItem(item:UniqueVO):void
		{
			var index:int = _items.getItemIndex(item);
			_items.removeItemAt(index);
		}
		
		/**
		 * Removes item by its UID
		 * */
		public function removeItemWithUid(uid:String):void
		{
			var item:UniqueVO = getItemByUid(uid);
			if (item != null)
				removeItem(item);
		}
		
		/**
		 * Removes item at selected position.
		 */
		public function removeItemAt(index:uint):void
		{
			_items.removeItemAt(index);
		}
		
		/**
		 * Removes all items
		 * */
		public function removeAllItems():void
		{
			_items.removeAll();
		}
		
		/**
		 * Return free uid with the smallest number
		 */
		public function generateFreeUID(baseString:String = null):String
		{
			var usedUidBase:String = (baseString == null) ? uidBase : baseString;
			var indexIsUsed:Boolean = true;
			var nextIndex:int = 0;
			
			while (indexIsUsed){
				indexIsUsed = false;
				nextIndex++;
				
				for (var i:int = 0; i < _items.length; i++){
					if (_items[i].uid == usedUidBase + String(nextIndex)){
						indexIsUsed = true;
						break;
					}
				}
			}
			return usedUidBase + String(nextIndex);
		}
		
		/**
		 * Checks if uid of item can be changed to new value.
		 */
		public function checkUID(item:UniqueVO, newUID:String):Boolean
		{
			for (var i:int = 0; i < _items.length; i++)
			{
				if (_items[i] != item && _items[i].uid == newUID)
				{
					return false;
				}
			}
			return true;
		}
		
		/**
		 * Checks UID if it isn't null, specifies new UID if it's null.
		 * Arbitrary uidBase can be specified to be used as base for UID in the case of generating new UID
		 * */
		protected function validateUID(item:UniqueVO, uidBase:String = null):void
		{
			if (!(!item.uid || item.uid == ""))
			{
				var validUID:Boolean = checkUID(item, item.uid);
				if (!validUID)
				{
					item.uid = null;
				}
			}
			if (!item.uid || item.uid == "")
			{
				item.uid = generateFreeUID(uidBase);
			}
		}
	}
}